package com.iwhalecloud.bss.kite.cucc.service.flow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import com.iwhalecloud.bss.kite.cart.common.util.KiteSessionUtil;
import com.iwhalecloud.bss.kite.cucc.common.callclient.HttpsCallClient;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.bss.hsf.baseinf.service.InfExchangeService;
import com.iwhalecloud.bss.kite.common.callclient.service.IOrderQueryService;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.entity.InfService;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.flow.IFlowService;
import com.iwhalecloud.bss.kite.cucc.client.dto.attr.AttrParam;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.FlowTrackInfo;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.FlowTrackReq;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.OneStopTrackInfoDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.OssTrackInfoDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.ProcessFlowchartDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.flow.TrackInfoDTO;
import com.iwhalecloud.bss.kite.cucc.client.vo.scene.OneStopTrackInfoVO;
import com.iwhalecloud.bss.kite.cucc.client.vo.scene.OssTrackInfoVO;
import com.iwhalecloud.bss.kite.cucc.client.vo.scene.ProcessFlowchartVO;
import com.iwhalecloud.bss.kite.cucc.client.vo.scene.TrackInfoVO;
import com.iwhalecloud.bss.kite.cucc.common.callclient.constant.CallClientEnum;
import com.iwhalecloud.bss.kite.cucc.common.callclient.service.ICuccQueryInfService;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalCallClientEnum;
import com.iwhalecloud.bss.kite.cucc.common.util.CommonUtil;
import com.iwhalecloud.bss.kite.cucc.common.util.KiteHttpsUtils;
import com.iwhalecloud.bss.kite.cucc.service.inf.InfServiceHelper;
import com.iwhalecloud.bss.kite.cucc.service.util.LocalTokenUtil;

import com.ztesoft.bss.common.util.SpringUtil;

/**
 * @author yangwj
 * @date 2020/5/7 17:56
 */
@Service
public class FlowService implements IFlowService {
    private static final ZSmartLogger LOGGER = ZSmartLogger.getLogger(FlowService.class);

    @Value("${interface.call.mode:hsf}")
    private String mode;

    @Override
    public TrackInfoVO getOrderProgressInfo(String orderId) {
        // 接口返回信息有误，为了不影响正常流程，临时解决方案捕获异常
        TrackInfoVO trackInfoVO = null;
        try {
            trackInfoVO = this.getProgressInfoById(orderId);
        }
        catch (Exception e) {
            LOGGER.error(e);
        }
        return trackInfoVO;
    }

    private TrackInfoVO getProgressInfoById(String orderId){
        //请求参数
        Map<String, String> header = new HashMap<>(1024);
        header.put("Cookie", "SESSION=" + KiteSessionUtil.getLocalSessionId());
        Map<String, String> param = new HashMap<>(1024);
        param.put("orderId",orderId);

        IOrderQueryService orderQueryService = SpringUtil.getBean(IOrderQueryService.class);
        InfService infService = orderQueryService.queryServiceBySvcCode(
				CallClientEnum.QRY_PROGRESS_INFO.getServiceCode(), CallClientEnum.QRY_PROGRESS_INFO.getCenterCode());

        if (infService == null) {
            ErrorConsts.SERVICE_UNREGISTERED.throwOut(
                CallClientEnum.QRY_PROGRESS_INFO.getCenterCode() + ":" + CallClientEnum.QRY_PROGRESS_INFO
                    .getServiceCode());
        }

        String rsp = KiteHttpsUtils.doGet(null, SpringUtil.getBean(ICuccQueryInfService.class).getUrlByType(infService), header, param);

        //发送Get请求
        JSONObject rspJson =  JSON.parseObject(rsp);
        if (rsp == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(CallClientEnum.QRY_ORDER_DETAIL.getServiceCode(), "获取订单跟踪进度信息", "获取订单跟踪进度信息失败");
        }
        JSONArray dataJson = rspJson.getJSONArray("data");
        if (dataJson == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(CallClientEnum.QRY_ORDER_DETAIL.getServiceCode(), "获取订单跟踪进度信息", "获取订单跟踪进度信息失败");
        }
        Iterator it = dataJson.iterator();
        TrackInfoVO trackInfoVO =  new TrackInfoVO();
        while (it.hasNext()){
            JSONObject obj = (JSONObject) it.next();
            //flow
            JSONArray flowArray =  obj.getJSONArray("flow");
            if (!KiteObjectUtils.isEmpty(flowArray)) {
                Iterator flowIterator = flowArray.iterator();
                while (flowIterator.hasNext()){
                    JSONObject flowObject = (JSONObject) flowIterator.next();
                    JSONArray flowData =  flowObject.getJSONArray("flowData");
                    if (!KiteObjectUtils.isEmpty(flowData)) {
                        this.getFlowData(trackInfoVO,flowData);
                    }
                }
            }

            //order
            JSONObject orderJson =  obj.getJSONObject("order");
            if (!KiteObjectUtils.isEmpty(orderJson)) {
                trackInfoVO.getTrackList().setOrderInfo(JSONObject.toJavaObject(orderJson,TrackInfoDTO.OrderInfo.class));
            }
        }
        return trackInfoVO;
    }


    private void getFlowData(TrackInfoVO trackInfoVO,JSONArray flowArray){
        Iterator it = flowArray.iterator();
        List<TrackInfoDTO.FlowInfo> flowInfos  = new ArrayList<>();
        TrackInfoDTO trackInfoDTO = new TrackInfoDTO();
        while (it.hasNext()){
            JSONObject obj = (JSONObject) it.next();
            TrackInfoDTO.FlowInfo flowInfo =JSONObject.toJavaObject(obj,TrackInfoDTO.FlowInfo.class);
            flowInfos.add(flowInfo);
        }

        Map<String, List<TrackInfoDTO.FlowInfo>> map = flowInfos.stream().collect(Collectors.groupingBy(TrackInfoDTO.FlowInfo::getFlowNodeName, LinkedHashMap::new, Collectors.toList()));

        trackInfoDTO.setFlowInfoList(map);
        trackInfoVO.setTrackList(trackInfoDTO);
    }

    /**
     * Description: <br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param orderId
     * @return <br>
     */
    @Override
    public OssTrackInfoVO getOssProgressInfo(String orderId, String taskCode) {
      //请求参数
        Map<String, String> header = new HashMap<>(1024);
        header.put("Cookie", "SESSION=" + KiteSessionUtil.getLocalSessionId());
        Map<String, String> param = new HashMap<>(1024);
        param.put("order_Id",orderId);
        param.put("task_code",taskCode);
        IOrderQueryService orderQueryService = SpringUtil.getBean(IOrderQueryService.class);
		InfService infService = orderQueryService.queryServiceBySvcCode(
				LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(),
				LocalCallClientEnum.QRY_OSS_PROGRESS.getCenterCode());

        if (infService == null) {
            ErrorConsts.SERVICE_UNREGISTERED.throwOut(
                LocalCallClientEnum.QRY_OSS_PROGRESS.getCenterCode() + ":" + LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode());
        }
        Map<String, String> bodys = new HashMap();
        String rsp = KiteHttpsUtils.doPost(null, SpringUtil.getBean(ICuccQueryInfService.class).getUrlByType(infService), header, param, bodys);
        JSONObject rspJson =  JSON.parseObject(rsp);
        if (rsp == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(), "获取OSS进度信息", "获取OSS进度信息失败");
        }
        JSONObject dataJson = null;
        // 查询报错的手，返回的数据结果和查询到数据时返回的数据结构不一致，查询不到数据时，在转换json对象时会报错，所以加了一个try catch
        try {
            dataJson = rspJson.getJSONObject("message");
        }
        catch(Exception e) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(), "获取OSS进度信息", rspJson.get("message"));
        }
        if (dataJson == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(), "获取OSS进度信息", "获取OSS进度信息失败");
        }
        JSONObject repBody = dataJson.getJSONObject("UNI_BSS_BODY");
        if (Objects.isNull(repBody)) {
        	ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(), "获取OSS进度信息", "获取OSS进度信息为空");
		}
        JSONObject queryOrderRsp = repBody.getJSONObject("QUERY_ORDER_RSP");

        if (ErrorConsts.SUCCESS.getCode().equals(queryOrderRsp.get("RESP_CODE"))) {
            JSONObject srvOrderList = queryOrderRsp.getJSONObject("CST_ORD").getJSONObject("SRV_ORD_LIST");
            JSONArray srvOrderArray = srvOrderList.getJSONArray("SRV_ORD");
            Iterator it = srvOrderArray.iterator();
            List<OssTrackInfoDTO.FlowInfo> flowInfos  = new ArrayList<>();
            OssTrackInfoDTO trackInfoDTO = new OssTrackInfoDTO();
            while (it.hasNext()){
                JSONObject obj = (JSONObject) it.next();
                JSONArray tacheInfoArray = obj.getJSONObject("TACHE_LIST").getJSONArray("TACHE_INFO");
                if (!KiteObjectUtils.isEmpty(tacheInfoArray)) {
                    Iterator tacheInfoIterator = tacheInfoArray.iterator();
                    while (tacheInfoIterator.hasNext()){
                        JSONObject tacheInfo = (JSONObject) tacheInfoIterator.next();
                        OssTrackInfoDTO.FlowInfo flowInfo =JSONObject.toJavaObject(tacheInfo,OssTrackInfoDTO.FlowInfo.class);
                        flowInfos.add(flowInfo);
                    }
                }
            }
            Map<String, List<OssTrackInfoDTO.FlowInfo>> map = flowInfos.stream().collect(Collectors.groupingBy(OssTrackInfoDTO.FlowInfo::getTacheName, LinkedHashMap::new, Collectors.toList()));
            trackInfoDTO.setFlowInfoList(map);
            OssTrackInfoVO trackInfoVO =  new OssTrackInfoVO();
            trackInfoVO.setTrackList(trackInfoDTO);
            return trackInfoVO;
        }
        else {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_OSS_PROGRESS.getServiceCode(), "获取OSS进度信息", queryOrderRsp.get("RESP_DESC"));
        }
        return new OssTrackInfoVO();
    }

    /**
     * Description: <br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param orderId
     * @param taskCode
     * @param taskId
     * @return <br>
     */
    @Override
    public OneStopTrackInfoVO getOneStopProgressInfo(String orderId, String taskCode, String taskId) {
      //请求参数
        Map<String, String> header = new HashMap<>(1024);
        header.put("Cookie", "SESSION=" + KiteSessionUtil.getLocalSessionId());
        Map<String, String> param = new HashMap<>(1024);
        param.put("order_Id",orderId);
        param.put("task_Code",taskCode);
        param.put("task_Id",taskId);

        IOrderQueryService orderQueryService = SpringUtil.getBean(IOrderQueryService.class);
		InfService infService = orderQueryService.queryServiceBySvcCode(
				LocalCallClientEnum.QRY_ONESTOP_PROGRESS_INFO.getServiceCode(),
				LocalCallClientEnum.QRY_ONESTOP_PROGRESS_INFO.getCenterCode());

        if (infService == null) {
            ErrorConsts.SERVICE_UNREGISTERED.throwOut(
                LocalCallClientEnum.QRY_ONESTOP_PROGRESS_INFO.getCenterCode() + ":" + LocalCallClientEnum.QRY_ONESTOP_PROGRESS_INFO.getServiceCode());
        }
        Map<String, String> bodys = new HashMap();
        String rsp = KiteHttpsUtils.doPost(null, SpringUtil.getBean(ICuccQueryInfService.class).getUrlByType(infService), header, param, bodys);
        if (rsp == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_ONESTOP_PROGRESS_INFO.getServiceCode(), "获取一站式进度信息", "获取一站式进度信息失败");
        }
        List rspJson =  (List) JSON.parse(rsp);
        List<OneStopTrackInfoDTO.FlowInfo> flowInfos  = new ArrayList<>();
        OneStopTrackInfoDTO trackInfoDTO = new OneStopTrackInfoDTO();
        if (!KiteObjectUtils.isEmpty(rspJson)) {
            Iterator tacheInfoIterator = rspJson.iterator();
            while (tacheInfoIterator.hasNext()){
                JSONObject dealInfo = (JSONObject) tacheInfoIterator.next();
                OneStopTrackInfoDTO.FlowInfo flowInfo =JSONObject.toJavaObject(dealInfo,OneStopTrackInfoDTO.FlowInfo.class);
                flowInfos.add(flowInfo);
            }
        }
        Map<String, List<OneStopTrackInfoDTO.FlowInfo>> map = flowInfos.stream().collect(Collectors.groupingBy(OneStopTrackInfoDTO.FlowInfo::getTaskName, LinkedHashMap::new, Collectors.toList()));
        trackInfoDTO.setFlowInfoList(map);
        OneStopTrackInfoVO trackInfoVO =  new OneStopTrackInfoVO();
        trackInfoVO.setTrackList(trackInfoDTO);
        return trackInfoVO;
    }

    /**
     * 获取流程图
     * @param orderId
     * @param worksheetType
     * @return
     */
    @Override
    public ProcessFlowchartVO getProcessFlowchart(String orderId,String worksheetType){
    	//请求参数
        Map<String, String> header = new HashMap<>(1024);
        header.put("Cookie", "SESSION=" + KiteSessionUtil.getLocalSessionId());
        Map<String, String> param = new HashMap<>(1024);
        param.put("taskId",orderId);
        param.put("worksheetType",worksheetType);

        IOrderQueryService orderQueryService = SpringUtil.getBean(IOrderQueryService.class);
        InfService infService = orderQueryService.queryServiceBySvcCode(
            LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getServiceCode(),
            LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getCenterCode());

        if (infService == null) {
            ErrorConsts.SERVICE_UNREGISTERED.throwOut(
                LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getCenterCode() + ":" + LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getServiceCode());
        }

        String rsp = KiteHttpsUtils.doGet(null, SpringUtil.getBean(ICuccQueryInfService.class).getUrlByType(infService), header, param);

        //发送Get请求
        JSONObject rspJson = JSON.parseObject(rsp);
        if (rsp == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getServiceCode(), "获取订单流程图信息", "获取订单流程图信息失败");
        }
        String dataJson = rspJson.getString("data");
        if (dataJson == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut(LocalCallClientEnum.QRY_PROCESS_FLOWCHART.getServiceCode(), "获取订单流程图信息", "获取订单流程图信息失败");
        }
        ProcessFlowchartVO processFlowchartVO = new ProcessFlowchartVO();
        List<ProcessFlowchartDTO> retList = new ArrayList<ProcessFlowchartDTO>();
        if (!KiteObjectUtils.isEmpty(dataJson)) {
        	List<JSONObject> dataList = Optional.ofNullable(JSON.parseObject(dataJson, List.class)).orElse(Collections.EMPTY_LIST);
            dataList.stream().forEach(t -> {
                Map temp  = JSON.parseObject(t.toString(), Map.class);
                retList.add((ProcessFlowchartDTO) KiteMapUtils.mapToBean(temp, ProcessFlowchartDTO.class));
            });
        	processFlowchartVO.setFlowchartList(retList);
        }

		return processFlowchartVO;

    }

    /**
     * 获取流程图
     * @param orderId
     * @param worksheetType
     * @return
     */
    @Override
    public ProcessFlowchartVO getOrderProcessFlowchart(String orderId,String worksheetType){
        Map<String, Object> requestMap = new HashMap<>();
        Map<String, String> param = new HashMap<>(1024);
        param.put("taskId",orderId);
        param.put("worksheetType",worksheetType);
        Map uniBssBody = new HashMap();
        uniBssBody.put("FLOWCHART_QUERY_REQ", param);

        requestMap.put("UNI_BSS_BODY", uniBssBody);
        requestMap.put("OP_CODE", "json_chinaUnicom_govEnterprise_orderCenter_flowchartQuery");
        String respStr;
        if (KiteStringUtils.isEqual(mode, "http")) {
            respStr = HttpsCallClient.postStringWithObject(LocalCallClientEnum.INF_COMMON_URL, requestMap, LocalTokenUtil.getHeaderMap());
        } else {
            InfExchangeService infExchangeService = SpringUtil.getBean("infExchangeService");
            respStr = infExchangeService.exchange(new JSONObject(requestMap));
        }

        JSONObject rspJson = JSON.parseObject(respStr);

        if (rspJson == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut("FLOWCHART_QUERY_REQ", "获取订单流程图信息", "获取订单流程图信息失败");
        }
        //接口异常信息提示
        Map respMap = JSON.parseObject(respStr, Map.class);
        Map headMap = MapUtils.getMap(respMap, "UNI_BSS_HEAD");
        if(!"00000".equals(MapUtils.getString(headMap, "RESP_CODE"))) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut("FLOWCHART_QUERY_REQ", "获取订单流程图信息", "获取订单流程图信息失败,调用接口状态编码为："+MapUtils.getString(headMap, "RESP_DESC"));
        }
        // 接口数据处理
        Map respBody = MapUtils.getMap(respMap, "UNI_BSS_BODY");
        Map getFlowChartRsp = MapUtils.getMap(respBody, "FLOWCHART_QUERY_RSP");
        String dataJson = getFlowChartRsp.get("data").toString();
        if (dataJson == null) {
            ErrorConsts.INF_INVOKE_ERROR.throwOut("FLOWCHART_QUERY_RSP", "获取订单流程图信息", "获取订单流程图信息失败");
        }
        ProcessFlowchartVO processFlowchartVO = new ProcessFlowchartVO();
        List<ProcessFlowchartDTO> retList = new ArrayList<ProcessFlowchartDTO>();
        if (!KiteObjectUtils.isEmpty(dataJson)) {
            List<JSONObject> dataList = Optional.ofNullable(JSON.parseObject(dataJson, List.class)).orElse(Collections.EMPTY_LIST);
            dataList.stream().forEach(t -> {
                Map temp  = JSON.parseObject(t.toString(), Map.class);
                retList.add((ProcessFlowchartDTO) KiteMapUtils.mapToBean(temp, ProcessFlowchartDTO.class));
            });
            processFlowchartVO.setFlowchartList(retList);
        }
        return processFlowchartVO;
    }


    /**
     * 查询流程轨迹信息
     * @author zhang.song
     * @date 2021-04-16 16:43
     * @param flowTrackReq
     * @return com.iwhalecloud.bss.kite.cucc.client.dto.flow.FlowTrackInfo
     */
    @Override
    public FlowTrackInfo getFlowTrack(FlowTrackReq flowTrackReq) {
        Map<String, Object> requestMap = new HashMap<>();
        Map uniBssBody = new HashMap();
        uniBssBody.put("GET_FLOW_TRACK_REQ", getReqParams(flowTrackReq));
        requestMap.put("UNI_BSS_BODY", uniBssBody);
        requestMap.put("OP_CODE", "json_jike_orderCenter_getFlowTrack");
        InfServiceHelper.adaptGray(requestMap, requestMap);
        String respStr;
        if (KiteStringUtils.isEqual(mode, "http")) {
            respStr = HttpsCallClient.postStringWithObject(LocalCallClientEnum.INF_COMMON_URL, requestMap, LocalTokenUtil.getHeaderMap());
        } else {
            InfExchangeService infExchangeService = SpringUtil.getBean("infExchangeService");
            respStr = infExchangeService.exchange(new JSONObject(requestMap));
        }

        FlowTrackInfo flowTrackInfo = new FlowTrackInfo();
        Map respMap = JSON.parseObject(respStr, Map.class);
        Map headMap = MapUtils.getMap(respMap, "UNI_BSS_HEAD");
        if(!"00000".equals(MapUtils.getString(headMap, "RESP_CODE"))) {
            flowTrackInfo.setCode(MapUtils.getString(headMap, "RESP_CODE"));
            flowTrackInfo.setMessage(MapUtils.getString(headMap, "RESP_DESC"));
            return flowTrackInfo;
        }

        Map respBody = MapUtils.getMap(respMap, "UNI_BSS_BODY");
        Map getFlowTrackRsp = MapUtils.getMap(respBody, "GET_FLOW_TRACK_RSP");
        if(!"0".equals(MapUtils.getString(getFlowTrackRsp, "STATUS"))) {
            flowTrackInfo.setCode(MapUtils.getString(getFlowTrackRsp, "STATUS"));
            flowTrackInfo.setMessage(MapUtils.getString(getFlowTrackRsp, "MESSAGE"));
            return flowTrackInfo;
        }

        Map<String, Object> flowData = CommonUtil.getMap(getFlowTrackRsp, "DATA");
        flowTrackInfo.setCode("00000");
        flowTrackInfo.setFlowData(flowData);
        return flowTrackInfo;
    }

    /**
     * 接口参数格式化为接口文档要求格式
     */
    private static Map<String, Object> getReqParams(FlowTrackReq flowTrackReq) {
        Map<String, Object> flowTrackReqMap = new HashMap<>();
        flowTrackReqMap.put("ORDER_ID", flowTrackReq.getOrderId());
        List<AttrParam> paramList = flowTrackReq.getParamList();
        if(paramList != null && paramList.size() > 0) {
            List<Map<String, String>> list = new ArrayList<>(paramList.size());
            Map<String, String> attrMap;
            for (AttrParam attrParam : paramList) {
                attrMap = new HashMap<>(4);
                attrMap.put("PARAM_CODE", attrParam.getParamCode());
                attrMap.put("PARAM_VALUE", attrParam.getParamValue());
                list.add(attrMap);
            }
            flowTrackReqMap.put("PARAM", list);
        }
        return flowTrackReqMap;
    }
}
